﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
using System.Linq.Expressions;
using System.Data;
using System.Data.Entity;

namespace Pasta.Medio.Domain
{
	public class Repository<T> : IRepository<T> where T : class
	{
		private IObjectSet<T> _objectSet;

		protected IObjectSet<T> ObjectSet
		{
			get
			{
				if (_objectSet == null)
				{
					_objectSet = Program.Context.CreateObjectSet<T>();
				}
				return _objectSet;
			}
		}

		public IQueryable<T> GetQuery()
		{
			return ObjectSet;
		}

		public IEnumerable<T> GetAll()
		{
			return GetQuery().ToList();
		}

		public IEnumerable<T> Find(
			Expression<Func<T, bool>> filter = null,
			string includeProperties = "")
		{
			var query = GetQuery();

			if (filter != null)
			{
				query = query.Where(filter);
			}

			var includes = includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (var includeProperty in includes)
			{
				query = query.Include(includeProperty);
			}

			return query;
		}

		public IEnumerable<T> Find(Func<T, bool> where)
		{
			return ObjectSet.Where<T>(where);
		}

		public T Single(Func<T, bool> where)
		{
			return ObjectSet.SingleOrDefault<T>(where);
		}

		public T First(Func<T, bool> where)
		{
			return ObjectSet.First<T>(where);
		}

		public virtual void Delete(T entity)
		{
			ObjectSet.DeleteObject(entity);
		}

		public virtual void Add(T entity)
		{
			ObjectSet.AddObject(entity);
		}

		public void Attach(T entity)
		{
			ObjectSet.Attach(entity);
		}

		public void SaveChanges()
		{
			Program.Context.SaveChanges();
		}
	}

	public static class Extensions
	{
		public static IQueryable<T> Include<T>(this IQueryable<T> query, string property)
		{
			var objectQuery = query as ObjectQuery<T>;
			if (objectQuery == null)
			{
				throw new NotSupportedException("Include can be called only on ObjectQuery");
			}
			return objectQuery.Include(property);
		}
	}
}
